package cn.etg.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class HttpServletRequest {

    private Socket socket;

    private String method;
    private String uri;
    private String protocol;
    private Map<String,String> headers = new HashMap<>();

    private String requestURI;
    private String queryString;
    private Map<String,String> parameters = new HashMap<>();

    public HttpServletRequest(Socket socket) throws IOException, EmptyRequestException {
        this.socket=socket;
        // 解析请求行
        parseRequestLine();
        // 解析消息头
        parseHeader();
        // 解析消息正文
        parseContent();
    }
    /**
     * 解析消息正文
     * 当请求方式为POST使用
     */
    private void parseContent() {
        System.out.println("开始解析消息正文======="+method);
        // 判断本次请求是否为POST请求
        if("post".equalsIgnoreCase(method)){
            // 获取Content-Length的值来确定正文长度
            String length = getHeader("Content-Length");
            if(length!=null){
                int contentLen = Integer.parseInt(length);
                System.out.println("获得正文长度"+contentLen);
                // 保存到字节数组中
                byte[] bytes = new byte[contentLen];
                try {
                    InputStream in = socket.getInputStream();
                    in.read(bytes);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                // 根据Content-Type来对正文进行操作
                String contentType = getHeader("Content-Type");
                // 判断是否为GET请求提交时，URI中?右侧的数据
                if("application/x-www-form-urlencoded".equalsIgnoreCase(contentType)){
                   String line =  new String(bytes, StandardCharsets.ISO_8859_1);
                    System.out.println("正文数据"+line);
                    parseParameters(line);
                }

            }
        }
    }

    private String getHeader(String name) {
        return headers.get(name);
    }

    /**
     * 解析消息头
     */
    private void parseHeader() throws IOException {
        // 消息头
        while(true){
          String  line = readLine();
            if(line.isEmpty()){
                break;
            }
            String[] data = line.split(":\\s");
            headers.put(data[0],data[1]);
        }
        System.out.println(headers);
    }
    /**
     * 解析请求行
     */
    private void parseRequestLine() throws IOException, EmptyRequestException {
        String line = readLine();
        System.out.println(line);
        if(line.isEmpty()){
            throw new EmptyRequestException();
        }

        // 分割请求行，将分割的内容分别存入method，uri，protocol中
        String[] strs = line.split("\\s");
        method=strs[0];
        uri=strs[1];
        protocol=strs[2];
        // 分别输出method，uri，protocol
        System.out.println("method："+method);
        System.out.println("uri："+uri);
        System.out.println("protocol："+protocol);
        // 调用解析URI
        parseURI();
    }
    // 进一步解析URI
    private void parseURI(){
    /*
    uri 的两种情况
    1.不包含参数
    例如：/index.html
    直接将uri的值赋给requestURI即可
    2.包含参数
    例如/regUser?username=tom&password=123456&nickname=tt&age=12
    将uri中“？”左侧的请求部分赋值给requestURI
    将uri中“？”右侧参数部分赋值给queryString

    将参数部分先按照“&”拆分出每一组参数，再将每一组参数按照“=”拆分为参数名和参数值
    并将参数名作为key，参数值作为value传入到parameters中。

    几个特殊情况
    1.表单中有空着不写的输入框
    例如用户名不填
    /regUser?username=&password=123456&&nickname=tt&age=12
    2.表单中如果所有输入框没有指定name的属性，此时表单提交则会忽略所有输入框
    /regUser?
     */

        String[] data = uri.split("\\?");
        requestURI = data[0];
        if(data.length>1){
            queryString = data[1];
            parseParameters(queryString);
        }
        System.out.println("requestURI:"+requestURI);
        System.out.println("queryString:"+queryString);
        System.out.println("parameters:"+parameters);
    }

    private void parseParameters(String line){
        // 处理queryString的中文数据
        try {
            line = URLDecoder.decode(line,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //paraArr:[username=zhangsan, password=123456, nickname=asan, age=22]
        String[] paraArr = line.split("&");
        //遍历每一组参数
        for (String para : paraArr){
            //para:username=
            String[] arr = para.split("=",2);
            //将参数名作为key,参数值作为value存入parameters
            parameters.put(arr[0], arr[1]);
        }
    }
    /**
     * 读取浏览器发送的一行字符串
     * @return
     * @throws IOException
     */
    private String readLine() throws IOException {
        InputStream in = socket.getInputStream();
        // 创建StringBuilder
        StringBuilder builder = new StringBuilder();
        // pre 记录上一次字符，cur记录本次字符
        char pre = 'a',cur='a';
        int d;
        while ((d=in.read())!=-1){
            cur = (char)d;
            if(pre==13&&cur==10){// 如果连续读取回车+换行则停止读取
                break;
            }
            builder.append(cur);
            pre = cur;// 再下次读取字符前，将本次读取字符的字符记录为“上一次读取的字符”
        }
        String line = builder.toString().trim();
        return line;
    }
    // method,uri,protocol 的getter setter
    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public String getRequestURI() {
        return requestURI;
    }

    public void setRequestURI(String requestURI) {
        this.requestURI = requestURI;
    }
    public String getParameter(String name){
        return parameters.get(name);
    }

}
